package database

import (
	"context"
	"dustbe/util"
	"errors"
	"fmt"

	"github.com/neo4j/neo4j-go-driver/v5/neo4j"
)

type DustUser struct {
	Id int64  `json:"id"`
	Name string	  `json:"name"`
	ImgUrl string	`json:"imgUrl"`
	HashedPassword string
}


func findUser(cypher string) (DustUser, error) {
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeRead,
	})

	var dustUser DustUser
	exist := false
	
	defer session.Close(context.TODO())
	result, err := session.Run(context.TODO(), cypher, nil)
	if err != nil {
		return dustUser, err
	}

	for result.Next(context.TODO()) {
		n, _ := result.Record().Get("n")
		node := n.(neo4j.Node)
		dustUser.Id = node.Id
		dustUser.ImgUrl = node.Props["imgUrl"].(string)
		dustUser.Name = node.Props["name"].(string)
		dustUser.HashedPassword = node.Props["hashedPassword"].(string)
		exist = true
	}
	if exist {
		return dustUser, nil
	} else {
		return dustUser, errors.New("用户不存在")
	}
}

func FindUserById(id int) (DustUser, error) {
	cypher := fmt.Sprintf("match (n:DustUser) where id(n)=%d return n", id)
	user, err := findUser(cypher)
	return user, err
}

func FindUserByName(name string) (DustUser, error) {
	cypher := fmt.Sprintf("match (n:DustUser{name:\"%s\"}) return n", name)
	user, err := findUser(cypher)
	return user, err
}

func SignUp(name, password, imgUrl string) (DustUser, error) {
	var dustUser DustUser

	if len(name) > 30 {
		return dustUser, errors.New("名字太长啦！最长只能放30个字符")
	}

	user, _ := FindUserByName(name)

	if len(user.Name) > 0 {
		return dustUser, errors.New("用户名" + name + "已经被注册！")
	}

	hashedPassword, err := util.Encrypte(password)

	if err != nil {
		return dustUser, err
	}
	cypher := fmt.Sprintf("create (n:DustUser{name:\"%s\",hashedPassword:\"%s\",imgUrl:\"%s\"}) return n",
		name, hashedPassword, imgUrl)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})

	
	defer session.Close(context.TODO())
	result, err := session.Run(context.TODO(), cypher, nil)
	exist := false

	if err != nil {
		fmt.Println(err.Error())
		return dustUser, err
	}

	for result.Next(context.TODO()) {
		n, _ := result.Record().Get("n")
		node := n.(neo4j.Node)
		dustUser.Id = node.Id
		dustUser.ImgUrl = node.Props["imgUrl"].(string)
		dustUser.Name = node.Props["name"].(string)
		dustUser.HashedPassword = node.Props["hashedPassword"].(string)
		exist = true
	}
	if exist {
		return dustUser, nil
	} else {
		return dustUser, errors.New("用户不存在")
	}
}

func SignInCookie(id int, password string) (DustUser, error) {
	user, err := FindUserById(id)
	if err != nil {
		return user, err
	}

	ok := util.ValidRawPasswordCorrect(user.HashedPassword, password)
	if !ok {
		return user, errors.New("密码错误")
	}
	user.HashedPassword = ""

	return user, nil
}


func SignIn(name, password string) (DustUser, error) {
	user, err := FindUserByName(name)
	if err != nil {
		return user, err
	}

	ok := util.ValidRawPasswordCorrect(user.HashedPassword, password)
	if !ok {
		return user, errors.New("密码错误")
	}
	user.HashedPassword = ""

	return user, nil
}

func UpdateUserInfo(id int, name, password, newPassword, imgUrl string) (DustUser, error) {
	var dustUser DustUser
	user, err := FindUserById(id)
	if err != nil {
		return dustUser, err
	}
	ok := util.ValidRawPasswordCorrect(user.HashedPassword, password)
	if !ok {
		return dustUser, errors.New("原密码错误")
	}

	hashedPassword, err := util.Encrypte(password)
	if err != nil {
		return dustUser, err
	}
	cypher := fmt.Sprintf("match (n:DustUser{name:\"%s\"}) set n.HashedPassword=%s set n.imgUrl=%s return n",
		name, hashedPassword, imgUrl)
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})

	defer session.Close(context.TODO())
	result, err := session.Run(context.TODO(), cypher, nil)
	exist := false

	if err != nil {
		fmt.Println(err.Error())
		return dustUser, err
	}

	for result.Next(context.TODO()) {
		n, _ := result.Record().Get("n")
		node := n.(neo4j.Node)
		dustUser.Id = node.Id
		dustUser.ImgUrl = node.Props["imgUrl"].(string)
		dustUser.Name = node.Props["name"].(string)
		dustUser.HashedPassword = node.Props["hashedPassword"].(string)
		exist = true
	}
	if exist {
		return dustUser, nil
	} else {
		return dustUser, errors.New("用户不存在")
	}
}

// 如果 len(hashedPassword) == 0 那么不需要修改
func ModifyUserInfo(id int, name, hashedPassword, imgUrl string) (DustUser, error) {
	var dustUser DustUser
	name, _ = util.AddDoubleQuote(name)
	imgUrl, _ = util.AddDoubleQuote(imgUrl)
	cypher := fmt.Sprintf("match (n:DustUser) where id(n)=%d set n.name=%s set n.imgUrl=%s", id, name, imgUrl)
	if len(hashedPassword) > 0 {
		hashedPassword, _ = util.AddDoubleQuote(hashedPassword)
		cypher += fmt.Sprintf(" set n.hashedPassword=%s", hashedPassword)
	}
	cypher += " return n;"
	session := Neo4jDriver.NewSession(neo4j.SessionConfig{
		AccessMode: neo4j.AccessModeWrite,
	})

	defer session.Close(context.TODO())
	result, err := session.Run(context.TODO(), cypher, nil)
	exist := false
	fmt.Println(cypher)
	if err != nil {
		return dustUser, errors.New("更新用户词条时发生错误")
	}

	for result.Next(context.TODO()) {
		n, _ := result.Record().Get("n")
		node := n.(neo4j.Node)
		dustUser.Id = node.Id
		dustUser.ImgUrl = node.Props["imgUrl"].(string)
		dustUser.Name = node.Props["name"].(string)
		dustUser.HashedPassword = node.Props["hashedPassword"].(string)
		exist = true
	}
	if exist {
		return dustUser, nil
	} else {
		return dustUser, errors.New("被修改的用户不存在")
	}
}